Skip to main content

IOC Triage

IOC Triage

Overview

This workflow automates end-to-end triage and enrichment of mixed indicators of compromise (IOCs) submitted as a single batch through a webhook. It detonates and classifies file hashes and uploaded samples in the Zynap Sandbox — Zynap's own behavioral malware-analysis engine — enriches network indicators (IPs and domains) with live WHOIS, DNS, and TLS lookups, and draws on Zynap's threat-actor intelligence to associate each identified malware family with the sector-relevant adversaries known to use it. It then cross-references a sample's detonation-time infrastructure against the rest of the batch, turning the sandbox's own findings into a hunting pivot. The result is a single, machine-readable decision log in which every verdict, score, confidence value, and recommended action is computed by deterministic code — the language model is used only to write the human-readable narrative and can never alter a decision.

Prerequisites

The workflow has no hard external dependency. Its one optional component is a custom agent (an LLM) used purely to write the narrative prose — it makes no triage decision, so the workflow always produces a complete, correct decision log whether or not the agent runs.

  • With an LLM API key: register a custom agent (provider + model) in your organization and attach it to the narrative-analyst node to get the executive summary and per-item narrative.
  • Without an API key: the custom agent is not strictly necessary — you don't need to set anything up. Simply enable continue_on_error on the narrative-analyst node: the deterministic triage still completes and the decision log is produced, only without the narrative prose.

If you do enable the narrative, this is the agent configuration we used, for reference — model of your choice, temperature: 0.2, everything else left at its default:

System prompt:

You are a senior SOC threat analyst. You DO NOT make triage decisions — a deterministic
engine has ALREADY decided every verdict. Your only job is to turn those decisions into
clear, defensible analyst prose.

Your input is a JSON triage report with `counts` and `items[]`. Each item has: `ioc`,
`type`, `sha256`, `verdict` (malicious | suspicious | benign | unknown | inconclusive |
analysis_failed | error), `severity`, `confidence`, `malware_family`, `attack_techniques[]`
(MITRE ATT&CK ids), `adversary_association` {`actor`, `candidates[]`, `basis`, `sector_relevance`},
`recommended_action` (block | monitor | ignore | submit_for_detonation | manual_review), and
`evidence[]`. There may also be a `rejected[]` list of malformed indicators.

Write:
- `executive_summary`: 2–4 sentences on the batch — how many indicators, the notable
malicious/suspicious findings, and any adversary relevant to the defended sector.
- one `items[]` entry per input item, each with a one-paragraph `narrative` that explains
THAT item's verdict strictly from its evidence, naming the malware family, ATT&CK
techniques, and attributed actor(s) when present.
- optional `batch_notes`: cross-indicator observations (e.g. a sample's extracted C2 also
appearing as a network indicator in the same batch) and a note on any rejected indicators.

Hard rules: you MUST NOT change, re-score, or contradict a verdict, severity, adversary_association, or
recommended action. NEVER introduce an IOC, actor, malware family, or technique that is not
already present in the input. If `adversary_association.actor` is null but `candidates` is non-empty,
say "associated with one of: …" and list them — do not pick one. Output prose only, matching
the schema exactly.

Output schema (JSON):

{
"properties": {
"batch_notes": {
"type": "string"
},
"executive_summary": {
"type": "string"
},
"items": {
"items": {
"properties": {
"ioc": {
"type": "string"
},
"narrative": {
"type": "string"
}
},
"required": [
"ioc",
"narrative"
],
"type": "object"
},
"type": "array"
}
},
"required": [
"executive_summary",
"items"
],
"type": "object"
}

How It Works

  1. Batch Webhook Intake: Receives a batch of mixed indicators (SHA-256 hashes, uploaded file samples, IP addresses, and domains) through the trigger's webhook endpoint, allowing any SIEM, SOAR, or script to submit a case and receive a decision.

  2. Payload Parsing and Validation: Executes a script to validate and deduplicate the submitted indicators, compute the SHA-256 of any uploaded sample, and reject unsupported inputs with a stated reason (the sandbox is keyed on SHA-256, so MD5/SHA-1 are refused explicitly rather than silently dropped).

  3. Lane Split: Routes indicators into two concurrent analysis lanes for type-appropriate enrichment:

    Branch A - File and Hash Intelligence (Zynap Sandbox):

    • Bulk Hash Lookup: Submits all hashes and sample SHA-256s to the Zynap Sandbox in a single bulk lookup, retrieving verdict, score, malware family, MITRE ATT&CK techniques, and contacted infrastructure for any previously analyzed sample.
    • On-Demand Detonation: For uploaded samples not yet seen, detonates the file live on Zynap's own sandbox infrastructure (Windows VMs), capturing real behavior — process, network, file-system, and registry activity, mapped MITRE ATT&CK techniques, and the infrastructure the sample reaches out to — then re-queries so newly analyzed samples are triaged with the same depth as known ones. The verdict comes from real execution, not a third-party reputation feed.
    • Hash Classification: Executes a deterministic script that assigns each file a verdict, severity, confidence, and recommended action from the sandbox result, and extracts the infrastructure the sample contacted during detonation for cross-indicator correlation.

    Branch B - Network Indicator Enrichment:

    • Per-Indicator Enrichment Loop: Iterates over each IP and domain, gathering WHOIS registration data (creation date, registrar, privacy), DNS records (A, MX, NS), and the TLS certificate issuer.
    • Network Classification: Executes a deterministic script that assigns each network indicator a verdict, severity, confidence band, and action from the observed signals, recording the evidence without over-reacting on thin data.
  4. Live Adversary Association: Queries Zynap's threat-actor intelligence live at runtime — a curated knowledge base that maps malware families and targeted sectors to the adversaries behind them — to associate each identified family with the sector-relevant threat actors that use it, scoped to a configurable target sector (default Finance). A single match is named as the association; several are listed as candidates; none is stated plainly. Because the lookup runs live, attribution reflects the current state of Zynap's intelligence rather than a stale snapshot, and it is framed as association — not incident attribution — since malware families are shared across actors.

  5. Cross-Indicator C2 Correlation: Cross-references the infrastructure a malicious sample contacted during detonation against every network indicator in the same batch. A network indicator that appears as contacted command-and-control infrastructure is escalated accordingly — turning an otherwise unremarkable domain or IP into an actionable block backed by a hard sandbox observation.

  6. Deterministic Triage Aggregation: Consolidates both lanes, the adversary association, and the C2 correlation into a single, strict, machine-readable triage decision per indicator — verdict, severity, confidence, adversary association, evidence, and recommended action — tolerating empty lanes so a batch of any composition still produces a clean result.

  7. Narrative Generation and Fusion: An AI agent writes an executive summary and per-indicator narrative around the completed decisions; a fusion step then re-asserts the deterministic verdicts on top of the prose, guaranteeing the language model can never change a verdict, score, or action.

  8. Decision Log Output: Emits the final decision log — the enriched, prioritized triage report an analyst acts on — as structured JSON ready for a ticketing system, SOAR playbook, or analyst review.

Who is this for?

  • SOC analysts triaging batches of indicators from SIEM alerts, phishing reports, or threat feeds
  • Incident response teams needing fast, evidence-backed verdicts with adversary context during an investigation
  • Threat intelligence analysts building malware profiles and associating families with sector-relevant actors
  • Detection engineers and SOAR/automation teams wiring a webhook-driven triage step into existing pipelines
  • MSSP and managed-SOC teams standardizing IOC triage across multiple client environments

What problem does this workflow solve?

  • Eliminates manual, indicator-by-indicator pivoting across the sandbox, WHOIS/DNS/TLS tooling, and threat-actor intelligence by consolidating all of it into one automated pass
  • Puts Zynap's own sandbox and threat-actor intelligence to work in a single pass — real behavioral detonation supplies the verdict, ATT&CK techniques, and the contacted infrastructure behind the C2 pivot, while the live threat-actor knowledge base supplies sector-relevant adversary context no reputation feed can
  • Provides a hunting pivot a flat reputation feed cannot: a parked domain or shared IP is escalated to block only because a sample in the same batch actually contacted it during detonation
  • Accelerates response by returning verdicts, severity, confidence, adversary association, and a recommended action in a single machine-readable decision log
  • Reduces false positives by grounding every verdict in a real observation — a sandbox detonation, a live WHOIS/DNS/TLS fact — and declining to guess when the evidence is thin
  • Enables trustworthy automation: because all decisions are computed by deterministic code and the language model only phrases them, hallucinated verdicts or attribution are structurally impossible
  • Standardizes IOC triage into a repeatable, auditable process that any team, SIEM, or SOAR can invoke and consume consistently

Known limits

  • Uploaded file size (~7.5 MB in practice). The webhook sits behind an API gateway with a hard 10 MiB request limit, and base64 encoding inflates a file by ~33% — so a submitted sample is capped at roughly 7.5 MB of raw bytes. For larger, or already-analyzed, files send the SHA-256 instead of the file.
  • Hashes are SHA-256 only. The Zynap Sandbox is keyed on SHA-256; MD5/SHA-1 are rejected with a stated reason rather than looked up.
  • Behavioral detonation needs a real executable. New samples are detonated in Windows sandbox VMs; non-executable inputs return analysis_failed.
  • Network verdicts are heuristic. They rest on live WHOIS/DNS/TLS signals, not an external reputation feed.
  • Adversary association needs a named family. Attribution fires only when the sandbox assigns a specific malware family that the threat-actor library knows; a generic classification (e.g. UNCLASSIFIED) yields no association — reported honestly, not treated as an error.
  • Action is advisory. The decision log recommends an action (block / monitor / …); enforcement is left to the consuming SIEM or SOAR.

Example inputs

Submit a batch of indicators to the workflow's webhook. Each indicator declares a type of hash, sample, ip, or domain.

A hash plus a domain it contacts — the batch-level C2 correlation escalates the otherwise-parked domain to block because a sample in the same batch reached it during detonation:

{
"case_id": "c2-pivot",
"iocs": [
{ "type": "hash", "value": "ebb107c3b5de886be97fc513a0d447c1529252ab416205cc911c548c223f116b" },
{ "type": "domain", "value": "wtqq.net" }
]
}

A single known-malicious hash of a named family (DRIDEX) — the live per-family lookup attributes it to sector-relevant threat actors and raises severity to critical:

{
"case_id": "attribution-demo",
"iocs": [
{ "type": "hash", "value": "5ee949a473b09d358816d635477c2a1af7f57c59a2a43d2058a77303a7803ceb" }
]
}

A file uploaded as base64 (type: "sample") — a sample not already known to the sandbox is detonated live in Windows VMs, then triaged with the same depth as a known one:

{
"case_id": "sample-detonation",
"iocs": [
{ "type": "sample", "file_name": "suspect.bin", "file_data": "TVqQAAMAAAAEAAAA…<base64-encoded file bytes>…" }
]
}

The file is base64-encoded; base64 overhead plus the gateway's 10 MiB request limit cap the raw file at roughly 7.5 MB. For larger or already-known files, send the SHA-256 instead. A new sample runs behavioral detonation, so its execution takes several minutes rather than the seconds a known-hash lookup needs.

Updated: 2026-07-23